package com.xiashitech.apiservice.api;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.xiashitech.apiservice.Constants.ErrorCode;
import com.xiashitech.apiservice.grpc.AgentStatusService;
import com.xiashitech.apiservice.service.IAgentSystemStatusService;
import com.xiashitech.interfaces.agent.constants.AgentStatus;
import com.xiashitech.interfaces.agent.dto.SystemInfoDTO;
import com.xiashitech.interfaces.apiservice.dto.system.SystemInfoRequest;
import com.xiashitech.interfaces.apiservice.dto.system.SystemInfoResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Controller
@RequiredArgsConstructor(onConstructor =@_(@Autowired))
@RequestMapping(value = "/v1/agent")
public class AgentStatusController {
    private static final Log log = LogFactory.get();

    private final IAgentSystemStatusService agentSystemStatusService;

    private final ExecutorService pushthreadpool = Executors.newSingleThreadExecutor();



    /**
     * agent向agentService同步agent的状态，该方法只支持systemId+microServiceId对应一条监控控制记录。
     * @param systemInfoRequest
     * @return
     */
    @RequestMapping(value = "/syncAgentStatus", method = RequestMethod.POST)
    @ResponseBody
    public SystemInfoResponse syncAgentStatus(@RequestBody SystemInfoRequest systemInfoRequest) {
        if(systemInfoRequest == null || systemInfoRequest.getId() == null || systemInfoRequest.getMicroServiceId() == null || systemInfoRequest.getAgentStatus() == null) {
            return SystemInfoResponse.builder().code(ErrorCode.RESULT_4014.getCode()).message(ErrorCode.RESULT_4014.getMessage()).build();
        }
        SystemInfoDTO systemInfoDTO = agentSystemStatusService.selectAgentStatusByCache(systemInfoRequest.getId(),systemInfoRequest.getMicroServiceId());
        if(systemInfoRequest.getAgentStatus() == AgentStatus.NOT_RUN.getValue()) {
            if(systemInfoDTO != null && systemInfoDTO.getAgentStatus() != null && systemInfoDTO.getAgentStatus() == AgentStatus.NOT_RUN.getValue()) {
                return SystemInfoResponse.builder().code(ErrorCode.RESULT_1002.getCode()).message(ErrorCode.RESULT_1002.getMessage()).build();
            }
        }
        if(systemInfoDTO == null) {
            agentSystemStatusService.insertAgentStatus(SystemInfoDTO.builder().id(systemInfoRequest.getId()).microServiceId(systemInfoRequest.getMicroServiceId()).agentStatus(systemInfoRequest.getAgentStatus()).build());
        } else if (systemInfoDTO != null) {
            if(systemInfoDTO.getAgentStatus() != null && systemInfoDTO.getAgentStatus() == AgentStatus.BY_PASS.getValue()) {
                return SystemInfoResponse.builder().code(ErrorCode.RESULT_1002.getCode()).message(ErrorCode.RESULT_1002.getMessage()).build();
            }
            agentSystemStatusService.updateAgentStatusByCache(systemInfoRequest.getId(), systemInfoRequest.getMicroServiceId(), systemInfoRequest.getAgentStatus(), Boolean.TRUE);
        }
        return SystemInfoResponse.builder().code(ErrorCode.RESULT_1001.getCode()).message(ErrorCode.RESULT_1001.getMessage()).build();
    }

    /**
     * agent向agentService同步agent的状态，该方法只支持systemId+microServiceId对应一条监控控制记录。
     * @param systemInfoRequest
     * @return
     */
    @RequestMapping(value = "/syncAgentHost", method = RequestMethod.POST)
    @ResponseBody
    public SystemInfoResponse syncAgentHost(@RequestBody SystemInfoRequest systemInfoRequest) {
        if(systemInfoRequest == null || systemInfoRequest.getId() == null || systemInfoRequest.getMicroServiceId() == null || systemInfoRequest.getHost() == null) {
            return SystemInfoResponse.builder().code(ErrorCode.RESULT_4014.getCode()).message(ErrorCode.RESULT_4014.getMessage()).build();
        }
        SystemInfoDTO systemInfoDTO = agentSystemStatusService.selectAgentStatusByCache(systemInfoRequest.getId(),systemInfoRequest.getMicroServiceId());
        if(systemInfoDTO == null) {
            return SystemInfoResponse.builder().code(ErrorCode.RESULT_4016.getCode()).message(ErrorCode.RESULT_4016.getMessage()).build();
        } else if (systemInfoDTO != null) {
            if(systemInfoDTO.getHost() != null && systemInfoDTO.getHost().equals(systemInfoRequest.getHost())) {
                return SystemInfoResponse.builder().code(ErrorCode.RESULT_1002.getCode()).message(ErrorCode.RESULT_1002.getMessage()).build();
            }
            agentSystemStatusService.updateAgentHostByCache(systemInfoRequest.getId(), systemInfoRequest.getMicroServiceId(), systemInfoRequest.getHost(), Boolean.FALSE);
        }
        return SystemInfoResponse.builder().code(ErrorCode.RESULT_1001.getCode()).message(ErrorCode.RESULT_1001.getMessage()).build();
    }
    /**
     * 设置某系统的agent为运行中或旁路状态
     * @param systemId 系统id
     * @param microServiceId 微服务id
     * @param resume true 运行中；false 旁路
     * @return
     */
    @RequestMapping(value = "/resumeOrNot", method = RequestMethod.GET)
    @ResponseBody
    public SystemInfoResponse resumeOrNot(@RequestParam("systemId") String systemId, @RequestParam(value="microServiceId",required = false) String microServiceId, @RequestParam("resume") Boolean resume) {
        systemId = systemId.replaceAll("\\s*", "");
        Optional<SystemInfoResponse> responseOptional = checkSystemNum(systemId);
        if(responseOptional.isPresent()) {
            return responseOptional.get();
        }
        if(resume) {
            if(microServiceId == null || "".equals(microServiceId.replaceAll("\\s*", ""))) {
                agentSystemStatusService.updateAgentStatus(SystemInfoDTO.builder().id(systemId).microServiceId(microServiceId).agentStatus(AgentStatus.RUNNING.getValue()).build());
            } else {
                agentSystemStatusService.updateAgentStatusByCache(systemId, microServiceId, AgentStatus.RUNNING.getValue(), Boolean.FALSE);
            }
        } else {
            if(microServiceId == null || "".equals(microServiceId.replaceAll("\\s*", ""))) {
                agentSystemStatusService.updateAgentStatus(SystemInfoDTO.builder().id(systemId).microServiceId(microServiceId).agentStatus(AgentStatus.BY_PASS.getValue()).build());
            } else {
                agentSystemStatusService.updateAgentStatusByCache(systemId, microServiceId, AgentStatus.BY_PASS.getValue(), Boolean.FALSE);
            }
        }
        // 往客户端推状态，线程启动前，数据库状态已修改；
        // 如果线程运行前，状态再修改，中间状态会丢失，不考虑；
        // 如果修改多次，可能因为乱序，造成 Agent 状态与服务端不一致，采用单线程的线程池进行串式推送，假设任务队列不会很大
        String finalSystemId = systemId;
        pushthreadpool.submit(()->{
            System.out.println("pushAgentStatusToAgent: " + finalSystemId + ":" + microServiceId);
            SystemInfoDTO systemInfoDTO = SystemInfoDTO.builder().id(finalSystemId).microServiceId(microServiceId).build();
            List<SystemInfoDTO> silist = agentSystemStatusService.selectAgentStatus(systemInfoDTO);
            System.out.println("pushAgentStatusToAgent, SystemInfoDTO: " + silist);
            SystemInfoResponse systemInfoResponse = SystemInfoResponse.builder().code(ErrorCode.RESULT_1001.getCode()).message(ErrorCode.RESULT_1001.getMessage()).systemInfos(silist).build();
            // 为避免循环引用，直接从 Spring 容器中获取
            AgentStatusService agentStatusService = SpringUtil.getBean(AgentStatusService.class);
            agentStatusService.pushAgentStatusToAgent(systemInfoResponse);
        });
        return SystemInfoResponse.builder().code(ErrorCode.RESULT_1001.getCode()).message(ErrorCode.RESULT_1001.getMessage()).build();
    }

    /**
     * 根据系统id(systemId)+微服务id(microServiceId)获取当前系统的agent状态
     * @param systemId
     * @return
     */
    @RequestMapping(value = "/agentStatus", method = RequestMethod.GET)
    @ResponseBody
    public SystemInfoResponse agentStatus(@RequestParam("systemId") String systemId, @RequestParam(value="microServiceId") String microServiceId) {
        systemId = systemId.replaceAll("\\s*", "");
        microServiceId = microServiceId.replaceAll("\\s*", "");
        if("".equals(systemId) || "".equals(microServiceId)) {
            return SystemInfoResponse.builder().code(ErrorCode.RESULT_4014.getCode()).message(ErrorCode.RESULT_4014.getMessage()).build();
        }
        long start = System.currentTimeMillis();
        SystemInfoDTO systemInfoDTO = agentSystemStatusService.selectAgentStatusByCache(systemId, microServiceId);
        long end = System.currentTimeMillis();
        if((end - start ) >= 2*1000) {
            log.info("WARN: selectAgentStatusByCache time is too long, elapsed(ms): {}",(end-start));
        }
        if(systemInfoDTO == null) {
            log.info("WARN: selectAgentStatusByCache({},{}) is null, it SHOULD be restart agent or be CREATE by manual.", systemId, microServiceId);
            return SystemInfoResponse.builder().code(ErrorCode.RESULT_4016.getCode()).message(ErrorCode.RESULT_4016.getMessage()).build();
        }
        return SystemInfoResponse.builder().code(ErrorCode.RESULT_1001.getCode()).message(ErrorCode.RESULT_1001.getMessage()).systemInfos(Arrays.asList(systemInfoDTO)).build();
    }

    /**
     * 根据条件获取系统的agent状态的列表，若传入参数为空则返回全部系统，不带分页
     * @param systemInfoRequest
     * @return
     */
    @RequestMapping(value = "/allSysAgentStatus", method = RequestMethod.POST)
    @ResponseBody
    public SystemInfoResponse allSysAgentStatus(@RequestBody(required = false) SystemInfoRequest systemInfoRequest) {
        List<SystemInfoDTO> systemInfoDTOS;
        if(systemInfoRequest == null) {
            systemInfoDTOS = agentSystemStatusService.selectAgentStatus(SystemInfoDTO.builder().build());
        } else {
            systemInfoDTOS = agentSystemStatusService.selectAgentStatus(SystemInfoDTO.builder().id(systemInfoRequest.getId()).microServiceId(systemInfoRequest.getMicroServiceId()).agentStatus(systemInfoRequest.getAgentStatus()).searchStartDate(systemInfoRequest.getSearchStartDate()).searchEndDate(systemInfoRequest.getSearchEndDate()).build());
        }
        return SystemInfoResponse.builder().code(ErrorCode.RESULT_1001.getCode()).message(ErrorCode.RESULT_1001.getMessage()).systemInfos(systemInfoDTOS).build();
    }

    /**
     * 接收agent的心跳信号
     * @param systemId
     * @param microServiceId
     * @return
     */
    @RequestMapping(value = "/heartBeat", method = RequestMethod.GET)
    @ResponseBody
    public SystemInfoResponse heartBeat(@RequestParam("systemId") String systemId, @RequestParam(value="microServiceId") String microServiceId) {
        systemId = systemId.replaceAll("\\s*", "");
        microServiceId = microServiceId.replaceAll("\\s*", "");
        if("".equals(systemId) || "".equals(microServiceId)) {
            return SystemInfoResponse.builder().code(ErrorCode.RESULT_4014.getCode()).message(ErrorCode.RESULT_4014.getMessage()).build();
        }
        agentSystemStatusService.updateAgentHeartBeatByCache(systemId,microServiceId);
        return SystemInfoResponse.builder().code(ErrorCode.RESULT_1001.getCode()).message(ErrorCode.RESULT_1001.getMessage()).build();
    }




    /**
     * 检查系统个数，大于1和等于0都返回错误提示。
     * @param systemId
     * @return
     */
    private Optional<SystemInfoResponse> checkSystemNum(String systemId) {
        if("".equals(systemId)) {
            return Optional.ofNullable(SystemInfoResponse.builder().code(ErrorCode.RESULT_4014.getCode()).message(ErrorCode.RESULT_4014.getMessage()).build());
        }
        List<SystemInfoDTO> systemInfoDTOS = agentSystemStatusService.selectAgentStatus(SystemInfoDTO.builder().id(systemId).build());
        if(systemInfoDTOS.size() == 0) {
            return Optional.ofNullable(SystemInfoResponse.builder().code(ErrorCode.RESULT_4016.getCode()).message(ErrorCode.RESULT_4016.getMessage()).build());
        }
        return Optional.empty();
    }
    public String test()
    {
        return "hello";
    }

}
